/* 
 * File:   Render.cpp
 * Authors: Gilberto Volpe Neto
 *          Gustavo Luvizotto Cesar
 * Created on March 22, 2013, 5:10 PM
 */

#include "Render.h"
#include "SpaceShip.h"

Render::Render() {

    end = leftButtonMouse = rightButtonMouse = false;
    angleX = angleY = angleZ = 0;

    posMouseX = posMouseY = 0;
    value = 150;

    this->camera = new Camera(0.0f, 0.0f, -SUN_RADIUS * 2, 0.0f, 0.0f, 1.0f);
}

void Render::doSomethingInInitialization() {

}

void Render::menu(int value) {

    Point3D point;

    std::vector<Objects*>::iterator it;

    switch (value) {
        case ADD_SUN:
            if (!this->planets[0]) {
                planets[0] = new Planet(SUN, point, 0.1f);
                planets[0]->setRadius(planets[0]->getRadius());
                listOfElements.push_back(planets[0]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[0]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[0]);
                }
            }
            break;
        case ADD_MER:
            if (!this->planets[1]) {
                planets[1] = new Planet(MER, point, 0.1f);
                planets[1]->setRadius(planets[1]->getRadius());
                listOfElements.push_back(planets[1]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[1]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[1]);
                }
            }
            break;
        case ADD_VEN:
            if (!this->planets[2]) {
                planets[2] = new Planet(VEN, point, 0.1f);
                planets[2]->setRadius(planets[2]->getRadius());
                listOfElements.push_back(planets[2]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[3]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[2]);
                }
            }
            break;
        case ADD_EAR:
            if (!this->planets[3]) {
                planets[3] = new Planet(EAR, point, 0.1f);
                planets[3]->setRadius(planets[3]->getRadius());
                listOfElements.push_back(planets[3]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[3]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[3]);
                }
            }
            break;
        case ADD_MAR:
            if (!this->planets[4]) {
                planets[4] = new Planet(MAR, point, 0.1f);
                planets[4]->setRadius(planets[4]->getRadius());
                listOfElements.push_back(planets[4]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[4]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[4]);
                }
            }
            break;
        case ADD_JUP:
            if (!this->planets[5]) {
                planets[5] = new Planet(JUP, point, 0.1f);
                planets[5]->setRadius(planets[5]->getRadius());
                listOfElements.push_back(planets[5]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[5]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[5]);
                }
            }
            break;
        case ADD_SAT:
            if (!this->planets[6]) {
                planets[6] = new Planet(SAT, point, 0.1f);
                planets[6]->setRadius(planets[6]->getRadius());
                listOfElements.push_back(planets[6]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[6]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[6]);
                }
            }
            break;
        case ADD_URA:
            if (!this->planets[7]) {
                planets[7] = new Planet(URA, point, 0.1f);
                planets[7]->setRadius(planets[7]->getRadius());
                listOfElements.push_back(planets[7]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[7]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[7]);
                }
            }
            break;
        case ADD_NET:
            if (!this->planets[8]) {
                planets[8] = new Planet(NET, point, 0.1f);
                planets[8]->setRadius(planets[8]->getRadius());
                listOfElements.push_back(planets[8]);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), planets[8]);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(planets[8]);
                }
            }
            break;
        case REM_SUN:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[0]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_MER:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[1]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_VEN:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[2]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_EAR:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[3]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_MAR:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[4]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_JUP:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[5]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_SAT:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[7]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case REM_URA:
            if (!this->planets[7]) {
                planets[7] = new Planet(URA, point, 0.1f);
                listOfElements.push_back(planets[7]);
            }
            break;
        case REM_NET:
            it = std::find(listOfElements.begin(), listOfElements.end(), planets[8]);
            if (it != listOfElements.end()) {
                listOfElements.erase(it);
            }
            break;
        case ADD_SPACESHIP:
            if (!space) {
                point._x = FACTOR_EAR;
                point._y = 0;
                point._z = -EAR_RADIUS / 1.5 - 1000;
                space = new SpaceShip(point, 1.0f, false);
                listOfElements.push_back(space);
            } else {
                it = std::find(listOfElements.begin(), listOfElements.end(), space);
                if (it == listOfElements.end()) {
                    listOfElements.push_back(space);
                }
            }
            break;
        case QUIT:
            exit(0);
            break;
    }
}

/*
 * Metodo para desenhar na tela
 */
void Render::display() {

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    if (camera)
        camera->cameraVision();

    std::vector<Objects*>::iterator it = std::find(listOfElements.begin(), listOfElements.end(), planets[0]);
    if (it != listOfElements.end()) {
        light.Activate();
    } else {
        light.Deactivate();
    }

    drawInterest();

    glFlush();
    glutSwapBuffers();
}

void Render::drawInterest() {

    std::vector<Objects *>::iterator it = listOfElements.begin();

    while (it != listOfElements.end()) {
        (*it)->drawObject();
        it++;
    }
}

void Render::doSomethingInTime() {

    std::vector<Objects*>::iterator it = listOfElements.begin();

    while (it != listOfElements.end()) {
        (*it)->specificUpdate();
        it++;
    }

    this->doSomethingInInitialization();
}

void Render::handleKeyPress(unsigned char key, GLint x, GLint y) {

    if (space)
        space->controlOfSpaceTranslation(key, x, y);

    if (key == 'o' || key == 'O') {
        if (camera)
            camera->setOrthogonal(!camera->isOrthogonal());
    }

    if (key == 'f' || key == 'F') {
        light.changeShadding();
    }

    if (key == 'q' || key == 'Q')
        exit(0);
}

void Render::handleKeyPressNumber(int key, GLint x, GLint y) {
    if (camera)
        camera->controlOfTranslation(key, x, y);
}

void Render::handleMouse(GLint button, GLint state, GLint x, GLint y) {

    if (state == GLUT_DOWN) {
        if (button == GLUT_LEFT_BUTTON) {
            leftButtonMouse = true;
        }
    } else {
        if (button == GLUT_LEFT_BUTTON)
            leftButtonMouse = false;
    }
}

void Render::handleMouseMotion(GLint x, GLint y) {
    GLdouble distFromCenterX = (((GLdouble) x) / ((GLdouble) SIDE_SIZE)) - 0.5;
    GLdouble distFromCenterY = (((GLdouble) y) / ((GLdouble) SIDE_SIZE)) - 0.5;

    if (leftButtonMouse) {
        camera->updateLook(distFromCenterX, distFromCenterY);
    }
}
